unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FFailureHandled: Boolean;
    procedure OnAsphyreCreate(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnAsphyreDestroy(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnDeviceInit(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnDeviceCreate(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnTimerReset(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure TimerEvent(Sender: TObject);
    procedure ProcessEvent(Sender: TObject);
    procedure RenderEvent(Sender: TObject);
    procedure HandleConnectFailure;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  System.Types
  , AsphyreDevice, AsphyreCanvas, AsphyreDX10Provider, AsphyreFactory
  , AsphyreEventSystem, AsphyreEvents, AsphyreTimer, AsphyreWindowsConnector
  , AsphyrePointFUtils, AsphyreUtils, AsphyreImages, AsphyreBitmapBMP
  , AsphyreBitmapPNG
  ;

var
  G_AsphyreDevice: TAsphyreDevice;
  G_AsphyreCanvas: TAsphyreCanvas;

  G_AsphyreBMPImage : TAsphyreImage;
  G_AsphyrePNGImage : TAsphyreImage;

{$R *.dfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Specify that DirectX 10 provider is to be used
  G_Factory.UseProvider(cProviderIDOfDirectX10);

  // This event is called when Asphyre components should be created
  G_EventAsphyreCreate.Subscribe(ClassName, OnAsphyreCreate);

  // This event is called when Asphyre components are to be freed
  G_EventAsphyreDestroy.Subscribe(ClassName, OnAsphyreDestroy);

  // This event is callled before creating Asphyre device to initialize its parameters
  G_EventDeviceInit.Subscribe(ClassName, OnDeviceInit);

  // This event is callled upon Asphyre device creation
  G_EventDeviceCreate.Subscribe(ClassName, OnDeviceCreate);

  // This event is called when creating device and loading data to let the application reset the timer so it does not stall
  G_EventTimerReset.Subscribe(ClassName, OnTimerReset);

  // Initialize and prepare the timer.
  G_Timer.OnTimer := TimerEvent;
  G_Timer.OnProcess := ProcessEvent;
  G_Timer.MaxFPS := 60;
  G_Timer.Enabled := True;

  // This variable tells that a connection failure to Asphyre device has been already handled
  FFailureHandled := False;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // Disconnect Asphyre device from FireMonkey
  if Assigned(G_AsphyreDevice) then
    G_AsphyreDevice.Disconnect;  // Finalize;

  // Finish the Asphyre connection manager
  G_WindowsConnector.Done;

  // Remove the subscription to the events
  G_EventProviders.Unsubscribe(ClassName);
end;

procedure TForm1.HandleConnectFailure;
begin
  G_Timer.Enabled := False;

  ShowMessage('Failed initializing Asphyre device.');
  Close;
end;

procedure TForm1.OnAsphyreCreate(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  // Create all Asphyre components
  G_AsphyreDevice := G_Factory.CreateDevice;
  G_AsphyreCanvas := G_Factory.CreateCanvas;
end;

procedure TForm1.OnAsphyreDestroy(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  G_Timer.Enabled := False;

  FreeAndNil(G_AsphyreCanvas);
  FreeAndNil(G_AsphyreDevice);
  FreeAndNil(G_AsphyreBMPImage);
  FreeAndNil(G_AsphyrePNGImage);
end;

procedure TForm1.OnDeviceCreate(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  PBoolean(Param)^ := True;

  G_AsphyreBMPImage := TAsphyreImage.Create;
  G_AsphyreBMPImage.LoadFromFile('0.bmp');

  G_AsphyrePNGImage := TAsphyreImage.Create;
  G_AsphyrePNGImage.LoadFromFile('0.png');
end;

procedure TForm1.OnDeviceInit(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
var
  DisplaySize: TPoint;
begin
  DisplaySize := Point(ClientWidth, ClientHeight);
  G_AsphyreDevice.SwapChains.Add(Handle, DisplaySize);
end;

procedure TForm1.OnTimerReset(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  G_Timer.Reset;
end;

procedure TForm1.ProcessEvent(Sender: TObject);
begin
  //
end;

procedure TForm1.RenderEvent(Sender: TObject);
begin
  G_AsphyreCanvas.DrawLine(10, 10, 110, 10, $FFFFFF00);
  G_AsphyreCanvas.DrawWuLine(PointF(10, 20), PointF(110, 20), $FFFF0000, $FF00FF00);
  // G_AsphyreCanvas.DrawEllipse(PointF(50, 50), PointF(20, 15), 90, $FFFFFFFF);
  G_AsphyreCanvas.DrawCircle(PointF(50, 50), 25, 90, $FFFFFFFF);
  G_AsphyreCanvas.DrawFilledRect(10, 100, 110, 100, $FF00FFFF);
  G_AsphyreCanvas.DrawFramedRect(Rect(10, 250, 110, 450), Color4From1Color($FF00FF00));

  G_AsphyreCanvas.DrawTexture(G_AsphyreBMPImage.Texture[0],
                              PointF4FromRect(Rect(150, 10, 662, 522)),
                              PointF4From4Coords(0, 0, 1, 0, 1, 1, 0, 1),
                              Color4From1Color($FFFFFFFF)
                             );

  G_AsphyreCanvas.DrawTexture(G_AsphyrePNGImage.Texture[0],
                              PointF4FromRect(Rect(670, 10, 1192, 522)),
                              PointF4From4Coords(0, 0, 1, 0, 1, 1, 0, 1),
                              Color4From1Color($FFFFFFFF)
                             );

  // scale
  G_AsphyreCanvas.DrawTexture(G_AsphyreBMPImage.Texture[0],
                              PointF4FromBoundsScaled(10, 500, 512, 512, 0.25),
                              PointF4From4Coords(0, 0, 1, 0, 1, 1, 0, 1),
                              Color4From1Color($FFFFFFFF)
                             );

  // mirror
  G_AsphyreCanvas.DrawTexture(G_AsphyreBMPImage.Texture[0],
                              PointF4Mirrored(PointF4FromRect(Rect(150, 525, 662, 780))),
                              PointF4From4Coords(0, 0, 1, 0, 1, 1, 0, 1),
                              Color4From1Color($FFFFFFFF)
                             );

  // flip
  G_AsphyreCanvas.DrawTexture(G_AsphyrePNGImage.Texture[0],
                              PointF4Fliped(PointF4FromRect(Rect(670, 525, 1192, 780))),
                              PointF4From4Coords(0, 0, 1, 0, 1, 1, 0, 1),
                              Color4From1Color($FFFFFFFF)
                             );
end;

procedure TForm1.TimerEvent(Sender: TObject);
begin
  // Try to connect Asphyre to the application
  if not G_WindowsConnector.Initialize then
    Exit;

  // In case the device could not be initialized properly (in the frame before
  // this one), show error message and close the form
  if Assigned(G_AsphyreDevice) and G_AsphyreDevice.IsAtFault then
  begin
    if not FFailureHandled then
      HandleConnectFailure;
    FFailureHandled := True;
    Exit;
  end;

  // Initialize Asphyre device, if needed. If this initialization fails, the
  // failure will be handled in the next OnTimer event
  if (not Assigned(G_AsphyreDevice)) or (not G_AsphyreDevice.Connect{Initialize}) then
    Exit;

  // Render the scene
  G_AsphyreDevice.Render(RenderEvent, $000050);

  // Execute constant time processing.
  G_Timer.Process;
end;

end.
